﻿#pragma execution_character_set("utf-8")

#include "WidgetPanel.h"

#include <QAction>
#include <QBoxLayout>
#include <QCheckBox>
#include <QIntValidator>
#include <QJsonArray>
#include <QJsonObject>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
#include <QStringList>

#include "MainWindow.h"
#include "SpiderDataDlg.h"
#include "TagsDlg.h"

QString html = R"(
        <div style="text-align: left; font-size: 40px;">
            <span style="color: red;">%1</span><br>          
            <span style="color: blue;">%2</span>
        </div>

    )";
WidgetPanel::WidgetPanel(QWidget *parent)
    : QWidget(parent)
    , m_dataMgr(DataMgr::getInstance())
{
}

QColor getLuoguColor(int nDiff)
{
    if (nDiff == 1) return QColor(254, 76, 76);
    if (nDiff == 2) return QColor(255, 140, 26);
    if (nDiff == 3) return QColor(255, 193, 22);
    if (nDiff == 4) return QColor(82, 196, 26);
    if (nDiff == 5) return QColor(52, 152, 219);
    if (nDiff == 6) return QColor(157, 61, 207);
    if (nDiff == 7) return QColor(14, 29, 105);

    return QColor(191, 191, 191);
}

void WidgetPanel::slotSearchAT()
{
    m_mainWindw->setTableMode(TableMode::ATCoder);
    m_dataMgr->m_bSearchCF = false;
    m_dataMgr->m_nRatingMin = m_edtATMin->currentData().toInt();
    m_dataMgr->m_nRatingMax = m_edtATMax->currentData().toInt();
    //   m_dataMgr->m_setLuoGuSearchTag = {"326"};

    std::vector<ATSearchOneProblem> vecSearch = m_dataMgr->searchAT();
    m_mainWindw->tableWidget->setRowCount(vecSearch.size());

    for (int i = 0; i < vecSearch.size(); ++i)
    {
        ATProblemRef p = vecSearch[i].problemRef;
        ATContestRef contest = vecSearch[i].contestRef;

        const bool bAC = m_dataMgr->m_setATMyProblem.find(p->key) !=
                         m_dataMgr->m_setATMyProblem.end();

        QStringList lstRow;
        lstRow << p->key.strProblemID << p->strProblemName
               << contest->strContestName << toString(contest->contestType)
               << QString::number(p->nDifficult)
               << contest->dt.toString("yyyy-MM-dd HH:mm:ss") << "null"
               << setToString(m_dataMgr->m_mapATProblemToUser[p->key])
               << tagToString(vecSearch[i].vecTag);

        const int nDiff = m_dataMgr->m_mapATLuoDifficulty[p->key];
        std::vector<QTableWidgetItem *> vecItem =
            m_mainWindw->appendOneRow(i, lstRow, true, getLuoguColor(nDiff),
                                      bAC ? QColor(0, 100, 0) : Qt::white);
        vecItem[0]->setData(Qt::UserRole, p->getURL());
    }
}

void WidgetPanel::slotSearchATFG()
{
    m_mainWindw->setTableMode(TableMode::ATCoder);
    m_dataMgr->m_bSearchCF = false;
    m_dataMgr->m_nRatingMin = m_edtATMin->currentData().toInt();
    m_dataMgr->m_nRatingMax = m_edtATMax->currentData().toInt();
    //   m_dataMgr->m_setLuoGuSearchTag = {"326"};

    const QStringList vecID = m_edtPara->text().split(" ");

    std::vector<ATSearchOneProblem> vecSearch = m_dataMgr->searchAT_FG(vecID);
    m_mainWindw->tableWidget->setRowCount(vecSearch.size());

    for (int i = 0; i < vecSearch.size(); ++i)
    {
        ATProblemRef p = vecSearch[i].problemRef;
        ATContestRef contest = vecSearch[i].contestRef;

        const bool bAC = m_dataMgr->m_setATMyProblem.find(p->key) !=
                         m_dataMgr->m_setATMyProblem.end();

        QStringList lstRow;
        lstRow << p->key.strProblemID << p->strProblemName
               << contest->strContestName << toString(contest->contestType)
               << QString::number(p->nDifficult)
               << contest->dt.toString("yyyy-MM-dd HH:mm:ss") << "null"
               << setToString(m_dataMgr->m_mapATProblemToUser[p->key])
               << tagToString(vecSearch[i].vecTag);

        const int nDiff = m_dataMgr->m_mapATLuoDifficulty[p->key];
        std::vector<QTableWidgetItem *> vecItem =
            m_mainWindw->appendOneRow(i, lstRow, true, getLuoguColor(nDiff),
                                      bAC ? QColor(0, 100, 0) : Qt::white);
        vecItem[0]->setData(Qt::UserRole, p->getURL());
    }
}

void WidgetPanel::slotBtnLoadWeb()
{
    SpiderDataDlg dlg;
    dlg.exec();
}

void WidgetPanel::slotSearchTags()
{
    TagsDlg dlg;
    if (1 != dlg.exec())
    {
        return;
    }
    const auto [strL, strCF] = m_dataMgr->getTags();

    QString ss = html.arg(strL).arg(strCF);
    m_labelTag->setText(ss);
}

QPushButton *WidgetPanel::createSpliterLine()
{
    QPushButton *btn = new QPushButton();
    QString qssStyle = R"(
        QPushButton {
            background-color: #2196F3;
            border: 0px;
        }
    )";
    btn->setStyleSheet(qssStyle);
    btn->setFixedHeight(2);
    return btn;
}

void WidgetPanel::slotSearchCF()
{
    m_mainWindw->setTableMode(TableMode::CF);
    m_dataMgr->m_bSearchCF = true;
    m_dataMgr->m_bUseCFTag = m_checkUseCFTag->checkState() == Qt::Checked;
    m_dataMgr->m_nRatingMin = m_edtCFMin->text().toInt();
    m_dataMgr->m_nRatingMax = m_edtCFMax->text().toInt();

    const QString strOtherUser = m_edtOtherUser->text().simplified();

    std::vector<CFSearchOneProblem> vecSearch = m_dataMgr->searchCF();
    m_mainWindw->tableWidget->setRowCount(0);

    int nNbRow = 0;
    for (int i = 0; i < vecSearch.size(); ++i)
    {
        CFProblemRef p = vecSearch[i].problemRef;
        CFContestRef contest = vecSearch[i].contestRef;

        const bool bAC = m_dataMgr->m_setCFMyProblem.find(p->key) !=
                         m_dataMgr->m_setCFMyProblem.end();

        const std::unordered_set<QString> &mapOtherUser =
            m_dataMgr->m_mapCFProblemToUser[p->key];
        if (!strOtherUser.isEmpty() &&
            mapOtherUser.find(strOtherUser) == mapOtherUser.end())
        {
            continue;
        }

        ++nNbRow;
        m_mainWindw->tableWidget->setRowCount(nNbRow);

        QStringList lstRow;
        lstRow << p->key.toString() << p->strProblemName
               << contest->strContestName << toString(contest->contestType)
               << QString::number(p->nRating)
               << contest->dt.toString("yyyy-MM-dd HH:mm:ss")
               << QString::number(p->nSolved)
               << setToString(m_dataMgr->m_mapCFProblemToUser[p->key])
               << tagToString(vecSearch[i].vecTag);

        std::vector<QTableWidgetItem *> vecItem =
            m_mainWindw->appendOneRow(nNbRow - 1, lstRow, true, p->getColor(),
                                      bAC ? QColor(0, 255, 0) : Qt::black);
        vecItem[0]->setData(Qt::UserRole, p->getURL());
    }
}

void WidgetPanel::slotSearchCFSomeOne()
{
    m_mainWindw->setTableMode(TableMode::CFSomeOne);
    m_dataMgr->m_bSearchCF = true;
    m_dataMgr->m_bUseCFTag = m_checkUseCFTag->checkState() == Qt::Checked;
    m_dataMgr->m_nRatingMin = m_edtCFMin->text().toInt();
    m_dataMgr->m_nRatingMax = m_edtCFMax->text().toInt();

    const QString strOtherUser = m_edtOtherUser->text().simplified();
    if (strOtherUser.isEmpty())
    {
        return;
    }

    std::vector<CFSearchSomeOne> vecSearch =
        m_dataMgr->searchCFSomeOne(strOtherUser);
    m_mainWindw->tableWidget->setRowCount(0);

    int nNbRow = 0;
    for (int i = 0; i < vecSearch.size(); ++i)
    {
        CFProblemRef p = vecSearch[i].problemRef;
        CFContestRef contest = vecSearch[i].contestRef;

        const bool bAC = m_dataMgr->m_setCFMyProblem.find(p->key) !=
                         m_dataMgr->m_setCFMyProblem.end();

        const std::unordered_set<QString> &mapOtherUser =
            m_dataMgr->m_mapCFProblemToUser[p->key];
        if (!strOtherUser.isEmpty() &&
            mapOtherUser.find(strOtherUser) == mapOtherUser.end())
        {
            continue;
        }

        ++nNbRow;
        m_mainWindw->tableWidget->setRowCount(nNbRow);

        QStringList lstRow;
        lstRow << p->key.toString() << p->strProblemName
               << contest->strContestName << toString(contest->contestType)
               << QString::number(p->nRating)
               << contest->dt.toString("yyyy-MM-dd HH:mm:ss")
               << QString::number(p->nSolved)
               << QString("第%1周").arg(vecSearch[i].nWeekIndex, 3, 10,
                                        QChar('0'))
               << tagToString(vecSearch[i].vecTag);

        std::vector<QTableWidgetItem *> vecItem =
            m_mainWindw->appendOneRow(nNbRow - 1, lstRow, true, p->getColor(),
                                      bAC ? QColor(0, 255, 0) : Qt::black);
        vecItem[0]->setData(Qt::UserRole, p->getURL());
    }
}

void WidgetPanel::setupUI()
{
    QVBoxLayout *layout = new QVBoxLayout();
    setLayout(layout);
    QPushButton *btn = nullptr;

    m_btnTag = new QPushButton("Tag设置");
    m_btnTag->setLayout(new QVBoxLayout());
    connect(m_btnTag, &QPushButton::clicked, this,
            &WidgetPanel::slotSearchTags);
    layout->addWidget(m_btnTag);

    m_labelTag = new QLabel();

    m_labelTag->setTextFormat(Qt::RichText);
    m_labelTag->setAlignment(Qt::AlignLeft);

    layout->addWidget(m_labelTag);

    m_checkUseCFTag = new QCheckBox("使用CF官方Tags");
    layout->addWidget(m_checkUseCFTag);
    m_checkUseCFTag->setChecked(false);
    layout->addStretch();

    layout->addWidget(createSpliterLine());
    layout->addSpacing(5);
    m_vecCheckContestType = {
        {Div1, new QCheckBox()},  {Div2, new QCheckBox()},
        {Div12, new QCheckBox()}, {CF_Other, new QCheckBox()},
        {Edu, new QCheckBox()},   {Div3, new QCheckBox()},
        {Div4, new QCheckBox()}};
    for (const auto &[_type, _check] : m_vecCheckContestType)
    {
        layout->addWidget(_check);

        connect(_check, &QCheckBox::clicked,
                [_type, _check, this]
                {
                    m_dataMgr->m_mapSearchContest[_type].bChecked =
                        _check->checkState() == Qt::Checked;
                });
    }

    QHBoxLayout *layoutCFRating = new QHBoxLayout();
    m_edtCFMin = new QLineEdit("1000");
    m_edtCFMax = new QLineEdit("1200");
    QIntValidator *validator = new QIntValidator(1, 5000, m_edtCFMin);
    m_edtCFMin->setValidator(validator);
    validator = new QIntValidator(1, 5000, m_edtCFMax);
    m_edtCFMax->setValidator(validator);

    layoutCFRating->addWidget(new QLabel("难度范围:"));
    layoutCFRating->addWidget(m_edtCFMin);
    layoutCFRating->addWidget(new QLabel("-"));
    layoutCFRating->addWidget(m_edtCFMax);

    m_edtOtherUser = new QLineEdit("liuenci");
    layout->addWidget(m_edtOtherUser);

    btn = new QPushButton("CF搜索(按难度)");
    connect(btn, &QPushButton::clicked, this, &WidgetPanel::slotSearchCF);
    layout->addLayout(layoutCFRating);
    layout->addWidget(btn);

    btn = new QPushButton("CF搜索(按周)");
    connect(btn, &QPushButton::clicked, this,
            &WidgetPanel::slotSearchCFSomeOne);
    layout->addLayout(layoutCFRating);
    layout->addWidget(btn);

    layout->addStretch();

    layout->addWidget(createSpliterLine());
    layout->addSpacing(5);

    std::vector<std::tuple<ContestType, QCheckBox *>> vecCheckContestTypeAT = {
        {AT_ABC, new QCheckBox()},
        {AT_ARC, new QCheckBox()},
        {AT_AGC, new QCheckBox()}};
    for (const auto &[_type, _check] : vecCheckContestTypeAT)
    {
        layout->addWidget(_check);
        m_vecCheckContestType.emplace_back(_type, _check);

        connect(_check, &QCheckBox::clicked,
                [_type, _check, this]
                {
                    m_dataMgr->m_mapSearchContest[_type].bChecked =
                        _check->checkState() == Qt::Checked;
                });
    }

    QHBoxLayout *layoutATRating = new QHBoxLayout();
    m_edtATMin = new QComboBox();
    m_edtATMin->setEditable(false);
    m_edtATMin->addItem("未评测", 0);
    m_edtATMin->addItem("入门", 1);
    m_edtATMin->addItem("普及−", 2);
    m_edtATMin->addItem("普及/提高−", 3);
    m_edtATMin->addItem("普及+/提高", 4);
    m_edtATMin->addItem("提高+/省选−", 5);
    m_edtATMin->addItem("省选/NOI−", 6);
    m_edtATMin->addItem("NOI/NOI+/CTSC", 7);
    m_edtATMin->setCurrentIndex(3);

    m_edtATMax = new QComboBox();
    m_edtATMax->setEditable(false);
    m_edtATMax->addItem("未评测", 0);
    m_edtATMax->addItem("入门", 1);
    m_edtATMax->addItem("普及−", 2);
    m_edtATMax->addItem("普及/提高−", 3);
    m_edtATMax->addItem("普及+/提高", 4);
    m_edtATMax->addItem("提高+/省选−", 5);
    m_edtATMax->addItem("省选/NOI−", 6);
    m_edtATMax->addItem("NOI/NOI+/CTSC", 7);
    m_edtATMax->setCurrentIndex(6);

    layoutATRating->addWidget(new QLabel("难度范围:"));
    layoutATRating->addWidget(m_edtATMin);
    layoutATRating->addWidget(new QLabel("-"));
    layoutATRating->addWidget(m_edtATMax);
    layout->addLayout(layoutATRating);
    btn = new QPushButton("AT搜索");
    connect(btn, &QPushButton::clicked, this, &WidgetPanel::slotSearchAT);
    layout->addWidget(btn);

    m_edtPara = new QLineEdit("f g");
    layout->addWidget(m_edtPara);

    btn = new QPushButton("AT搜索(E/F/G)");
    connect(btn, &QPushButton::clicked, this, &WidgetPanel::slotSearchATFG);
    layout->addWidget(btn);

    layout->addStretch();

    layout->addWidget(createSpliterLine());
    layout->addSpacing(5);

    // auto btn6 = new QPushButton("打印其他人最近N周");
    // connect(btn6, &QPushButton::clicked, this, &WidgetPanel::slotPrintOther);
    // layout->addWidget(btn6);

    auto btn7 = new QPushButton("打印某人全部提交");
    connect(btn7, &QPushButton::clicked, this, &WidgetPanel::slotPrintSome);
    //   layout->addWidget(btn7);

    btn = new QPushButton("爬数据");
    connect(btn, &QPushButton::clicked, this, &WidgetPanel::slotBtnLoadWeb);
    layout->addWidget(btn);
}

void WidgetPanel::configToUI()
{
    auto &mp = m_dataMgr->searchContestInfo();
    for (const auto &[_type, _check] : m_vecCheckContestType)
    {
        auto nTmp = mp[_type].nNbOfContest;
        if (nTmp < 0)
        {
            nTmp = m_dataMgr->getContestNb(_type);
        }
        QString str = "%1(%2/%3)";
        _check->setText(str.arg(toString(_type))
                            .arg(nTmp)
                            .arg(m_dataMgr->getContestNb(_type)));
        _check->setChecked(mp[_type].bChecked);
    }
}

#include <QFileInfo>
#include <fstream>

bool writeVectorWithStd(const std::vector<QString> &data,
                        const QString &filename)
{
    std::ofstream file(filename.toStdString());
    if (!file.is_open())
    {
        qDebug() << "无法打开文件:" << filename;
        return false;
    }

    for (const QString &str : data)
    {
        file << str.toStdString() << "\n";
    }

    file.close();
    qDebug() << "标准库写入成功:" << filename;
    return true;
}

void WidgetPanel::slotPrintSome()
{
    QString str = m_edtOtherUser->text().simplified();

    const QString strFile = m_dataMgr->m_strDataDir + "/temp-some.txt";

    const std::vector<QString> vecLine = m_dataMgr->getUserStatics(str);
    writeVectorWithStd(vecLine, strFile);

    QUrl fileUrl = QUrl::fromLocalFile(QFileInfo(strFile).absoluteFilePath());
    QDesktopServices::openUrl(fileUrl);
}

void WidgetPanel::slotPrintOther()
{
    QString str = m_edtPara->text();
    int nPos = str.indexOf(" ");
    if (nPos == -1) return;

    int nStart = str.left(nPos).toInt();
    int nEnd = str.right(str.size() - nPos - 1).toInt();

    const std::vector<QString> vecLine =
        m_dataMgr->getUserStatics(nStart, nEnd);

    const QString strFile = m_dataMgr->m_strDataDir + "/temp-statics.txt";
    writeVectorWithStd(vecLine, strFile);

    QUrl fileUrl = QUrl::fromLocalFile(QFileInfo(strFile).absoluteFilePath());
    QDesktopServices::openUrl(fileUrl);
}

QString WidgetPanel::tagToString(const std::vector<QString> &vecTag)
{
    QString strRet;

    for (const auto &s : vecTag)
    {
        auto it = m_dataMgr->m_mapTagZh.find(s);
        if (it == m_dataMgr->m_mapTagZh.end())
        {
            strRet += (s + ", ");
        }
        else
        {
            strRet += (it->second + ", ");
        }
    }

    return strRet;
}

QString WidgetPanel::setToString(const std::unordered_set<QString> &setStr)
{
    QString strRet;
    for (const auto &s : setStr) strRet += (s + ",");
    return strRet;
}
